import datetime
import logging
from datetime import timedelta

from src.core.models.dto.subscription import SubscriptionDTO
from src.core.models.enums import SubscriptionStatus, SubscriptionType
from src.core.utils.date_time import get_date_time
from src.database.converters.subscription import convert_db_model_to_subscription_dto
from src.database.models import Subscription, User
from src.database.uow import SQLAlchemyUoW

logger = logging.getLogger(__name__)


class SubscriptionService:
    def __init__(self, uow: SQLAlchemyUoW):
        self._uow = uow

    async def get_subscription_by_id(self, subscription_id: int) -> SubscriptionDTO:
        """Получаем подписку по id"""

        return await self._uow.subscription_reader.get_subscription_by_id(
            subscription_id
        )

    async def get_active_user_subscription(
        self, user_tg_id: int
    ) -> SubscriptionDTO | None:
        """Получаем активную подписку пользователя"""

        return await self._uow.subscription_reader.get_active_user_subscription(
            user_tg_id
        )

    async def get_subscription_with_activation_code(
        self, user_tg_id: int, activation_code_id: int
    ) -> SubscriptionDTO | None:
        """Получаем подписку пользователя с кодом активации"""

        return (
            await self._uow.subscription_reader.get_subscription_with_activation_code(
                user_tg_id, activation_code_id
            )
        )

    async def get_subscriptions(self) -> list[SubscriptionDTO]:
        """Получаем все доступные подписки"""

        return await self._uow.subscription_reader.get_subscriptions()

    async def get_expiring_subscriptions(self) -> list[SubscriptionDTO]:
        """Получаем подписки с истекающим сроке действия"""

        return await self._uow.subscription_reader.get_expiring_subscriptions()

    async def get_expired_subscriptions(self) -> list[SubscriptionDTO]:
        """Получаем закончившиеся подписки"""

        return await self._uow.subscription_reader.get_expired_subscriptions()

    async def create_subscription(
        self,
        user_tg_id: int,
        subscription_type: SubscriptionType,
        activation_code_id: int | None = None,
    ) -> SubscriptionDTO:
        """Создаем подписку"""

        user: User = await self._uow.user_repo.acquire_user_by_tg_id(user_tg_id)
        end_date = get_date_time() + timedelta(days=30)
        subscription = Subscription(
            user_id=user.id,
            subscription_type=subscription_type,
            activation_code_id=activation_code_id,
            end_date=end_date,
        )
        try:
            await self._uow.subscription_repo.create_subscription(subscription)
        except Exception as err:
            await self._uow.rollback()
            raise err

        await self._uow.commit()

        logger.info(f"Subscription was created: {subscription.id}")

        return convert_db_model_to_subscription_dto(subscription)

    async def extend_subscription(
        self, subscription_id: int, end_date: datetime.datetime
    ):
        """Продлеваем подписку на месяц"""

        subscription: Subscription = (
            await self._uow.subscription_repo.acquire_subscription_by_id(
                subscription_id
            )
        )
        subscription.end_date = end_date

        await self._uow.subscription_repo.update_subscription(subscription)

        await self._uow.commit()

        logger.info(f"Subscription №{subscription.id} was extended")

    async def update_subscription_status(
        self, subscription_id: int, status: SubscriptionStatus
    ):
        """Обновляем статус подписки"""

        subscription: Subscription = (
            await self._uow.subscription_repo.acquire_subscription_by_id(
                subscription_id
            )
        )
        subscription.status = status

        await self._uow.subscription_repo.update_subscription(subscription)

        await self._uow.commit()

        logger.info(
            f"Subscription №{subscription.id} status changed. New status: {status}"
        )

    async def update_subscription_notify_sent(self, subscription_id: int):
        """Обновляем уведомление подписки"""

        subscription: Subscription = (
            await self._uow.subscription_repo.acquire_subscription_by_id(
                subscription_id
            )
        )
        subscription.notify_sent = True

        await self._uow.subscription_repo.update_subscription(subscription)

        await self._uow.commit()
